#include <kuai/misc/typedef.hpp>

#ifndef _KUAI_MISC_MATRIX_
#define _KUAI_MISC_MATRIX_

namespace kuai { 

	template<typename T>
		class Matrix
	{
	public:
		typedef T ValueType;
		typedef std::pair<size_t, size_t> SizeType;

	public:
		explicit Matrix(SizeType size = SizeType(0, 0), ValueType v = ValueType()) 
		{ 
			reset(size, v);
		}
		explicit Matrix(size_t n, size_t m, ValueType v = ValueType()) 
		{ 
			reset(n, m, v);
		}

		Matrix(const Matrix& v0) {
            reset(v0.size());
			std::copy(v0._data.begin(), v0._data.end(), _data.begin());
		}
		Matrix& operator=(const Matrix& v0) {
			if (&v0 != this) {
                reset(v0.size());
				std::copy(v0._data.begin(), v0._data.end(), _data.begin());
			}
			return Me;
		}

	public:
		SizeType size() const {
			return _size;
		}
        		
		ValueType* operator[](size_t i) {
			return _pointer[i];
		}


		const ValueType* operator[](size_t i) const {
			return _pointer[i];
		}

		ValueType** pointer() 
		{ 
			return &_pointer[0];
		}

		Matrix& operator*=(ValueType v) 
		{
			for (typename std::vector<ValueType>::iterator 
				i = _data.begin(); i != _data.end(); ++i)
			{ 
				*i *= v;
			}
			return Me;
		}
		const Matrix operator*(ValueType v) const
		{
			Matrix result(Me);
			result *= v;
			return result;
		}

	public:
		void reset(SizeType s, ValueType v = ValueType()) {
			_size = s;
			_data.clear();
			_data.resize(s.first * s.second, v);
			_pointer.resize(s.first);
			for (size_t i = 0; i < s.first; ++i)
			{
				_pointer[i] = &_data[i*s.second];
			}
		}

		void reset(size_t n, size_t m, ValueType v = ValueType()) {
			reset(std::make_pair(n, m), v);
		}

		void swap(Matrix& v2)
		{ 
			_data.swap(v2._data);
			_pointer.swap(v2._pointer);
			std::swap(_size, v2._size);
		}

		bool empty() const
		{ 
			return _data.empty();
		}

		size_t row() const
		{ 
			return _size.first;
		}
		size_t column() const
		{ 
			return _size.second;
		}

	public:
		// The function return a unit matrix.
		static const Matrix<ValueType> unit(size_t n) { 
			Matrix result(n, n, 0);
			for (size_t i = 0; i < n; ++i) { 
				result[i][i] = 1;
			}
			return result;
		}

	private:
		std::vector<ValueType> _data;
		std::vector<ValueType*> _pointer;
		SizeType		_size;	// size;

	};

	template<typename ValueType>
	void swap(Matrix<ValueType>& v1, Matrix<ValueType>& v2) 
	{
        v1.swap(v2);		
	}

	template<typename ValueType>
	const Matrix<ValueType> operator*(ValueType v1, const Matrix<ValueType>& v2)
	{
		Matrix<ValueType> result(v2);
		result *= v1;
		return result;
	}

	typedef Matrix<int>			IntMatrix;
	typedef Matrix<RealNumber>	RealMatrix;
}

#endif
